The Memory Manager provides routines that allow you to purge and later reallocate space for relocatable blocks and control where in their heap zone relocatable blocks are located.
To free the memory taken up by a relocatable block without releasing the master pointer to the block for other uses, use the EmptyHandle procedure. To reallocate space for a handle that you have emptied or the Memory Manager has purged, use the ReallocateHandle procedure.
To ensure that a relocatable block that you plan to lock for short or long periods of time does not cause heap fragmentation, use the MoveHHi and the ReserveMem procedures, respectively.
The EmptyHandle procedure allows you to free memory taken by a relocatable block without freeing the relocatable block's master pointer for other uses.
PROCEDURE EmptyHandle (h: Handle);
The EmptyHandle procedure purges the relocatable block whose handle is h and sets the handle's master pointer to NIL . The block whose handle is h must be unlocked but need not be purgeable.
If there are multiple handles to the relocatable block, then calling the EmptyHandle procedure empties them all, because all of the handles share a common master pointer. When you later use ReallocateHandle to reallocate space for the block, the master pointer is updated, and all of the handles reference the new block correctly.
To free the memory taken up by a relocatable block and release the block's master pointer for other uses, use the DisposeHandle procedure, described on DisposeHandle .
To recover space for a relocatable block that you have emptied or the Memory Manager has purged, use the ReallocateHandle procedure.
PROCEDURE ReallocateHandle (h: Handle; logicalSize: Size);
The ReallocateHandle procedure allocates a new relocatable block with a logical size of logicalSize bytes. It updates the handle h by setting its master pointer to point to the new block. The new block is unlocked and unpurgeable.
Usually you use ReallocateHandle to reallocate space for a block that you have emptied or the Memory Manager has purged. If the handle references an existing block, ReallocateHandle releases that block before creating a new one.
To reallocate space for a resource that has been purged, you should call LoadResource , not ReallocateHandle .
If many handles reference a single purged, relocatable block, you need to call ReallocateHandle on just one of them.
In case of an error, ReallocateHandle neither allocates a new block nor changes the master pointer to which handle h points.
Because ReallocateHandle might purge and allocate memory, you should not call it at interrupt time.
Use the ReserveMem procedure when you allocate a relocatable block that you intend to lock for long periods of time. This helps prevent heap fragmentation because it reserves space for the block as close to the bottom of the heap as possible. Consistent use of ReserveMem for this purpose ensures that all locked, relocatable blocks and nonrelocatable blocks are together at the bottom of the heap zone and thus do not prevent unlocked relocatable blocks from moving about the zone.
PROCEDURE ReserveMem (cbNeeded: Size);
The ReserveMem procedure attempts to create free space for a block of cbNeeded contiguous logical bytes at the lowest possible position in the current heap zone. It pursues every available means of placing the block as close as possible to the bottom of the zone, including moving other relocatable blocks upward, expanding the zone (if possible), and purging blocks from it.
Because ReserveMem does not actually allocate the block, you must combine calls to ReserveMem with calls to the NewHandle function.
Do not use the ReserveMem procedure for a relocatable block you intend to lock for only a short period of time. If you do so and then allocate a nonrelocatable block above it, the relocatable block becomes trapped under the nonrelocatable block when you unlock that relocatable block.
It isn't necessary to call ReserveMem to reserve space for a nonrelocatable block, because the NewPtr function calls it automatically. Also, you do not need to call ReserveMem to reserve memory before you load a locked resource into memory, because the Resource Manager calls ReserveMem automatically.
Because the ReserveMem procedure could move and purge memory, you should not call it at interrupt time.
If you plan to lock a relocatable block for a short period of time, use the MoveHHi procedure, which moves the block to the top of the heap and thus helps prevent heap fragmentation.
PROCEDURE MoveHHi (h: Handle);
The MoveHHi procedure attempts to move the relocatable block referenced by the handle h upward until it reaches a nonrelocatable block, a locked relocatable block, or the top of the heap.
If you call MoveHHi to move a handle to a resource that has its resChanged bit set, the Resource Manager updates the resource by using the WriteResource procedure to write the contents of the block to disk. If you want to avoid this behavior, call the Resource Manager procedure SetResPurge(FALSE) before you call MoveHHi , and then call SetResPurge(TRUE) to restore the default setting.
By using the MoveHHi procedure on relocatable blocks you plan to allocate for short periods of time, you help prevent islands of immovable memory from accumulating in (and thus fragmenting) the heap.
Do not use the MoveHHi procedure to move blocks you plan to lock for long periods of time. The MoveHHi procedure moves such blocks to the top of the heap, perhaps preventing other blocks already at the top of the heap from moving down once they are unlocked. Instead, use the ReserveMem procedure before allocating such blocks, thus keeping them in the bottom partition of the heap, where they do not prevent relocatable blocks from moving.
If you frequently lock a block for short periods of time and find that calling MoveHHi each time slows down your application, you might consider leaving the block always locked and calling the ReserveMem procedure before allocating it.
Once you move a block to the top of the heap, be sure to lock it if you do not want the Memory Manager to move it back to the middle partition as soon as it can. (The MoveHHi procedure cannot move locked blocks; be sure to lock blocks after, not before, calling MoveHHi .)
Using the MoveHHi procedure without taking other precautionary measures to prevent heap fragmentation is useless, because even one small nonrelocatable or locked relocatable block in the middle of the heap might prevent MoveHHi from moving blocks to the top of the heap.
Because the MoveHHi procedure moves memory, you should not call it at interrupt time.
Don't call MoveHHi on blocks in the system heap. Don't call MoveHHi from a desk accessory.
You can use the HLockHi procedure to move a relocatable block to the top of the heap and lock it.
PROCEDURE HLockHi (h: Handle);
The HLockHi procedure attempts to move the relocatable block referenced by the handle h upward until it reaches a nonrelocatable block, a locked relocatable block, or the top of the heap. Then HLockHi locks the block.
The HLockHi procedure is simply a convenient replacement for the pair of procedures MoveHHi and HLock .
Because the HLockHi procedure moves memory, you should not call it at interrupt time.
Don't call HLockHi on blocks in the system heap. Don't call HLockHi from a desk accessory.